//
//  DataRepository.swift
//  
//
//  Created by tank on 2021/10/15.
//

import Foundation
import RxSwift
import DictionaryCoding
import Logging

open class BaseDataRepository<T>: DataRepositoryProtocol {
    
    var logger = Logger(label: "LibBase.DataRepository")
    
    
    open class var id: String {
        return "DataRepository"
    }
    
    private let disposeBag = DisposeBag()
    
    public var dataChangeCallBack: ((_ encodeData: Any?) -> Void)?
    
    public var itemChangeCallBack: ((_ encodeItem: Any?) -> Void)?
    
    public private(set) var data: T?
    
    public let dataObservable = PublishSubject<T?>()
    
    
    public convenience required init() {
        self.init(data: nil)
    }
    
    public init(data: T?) {
        self.data = data
        
        logger.logLevel = .debug
        
        dataObservable
            .subscribe { [weak self] _ in
                guard let strongSelf = self else {
                    return
                }
                
                strongSelf.dataChangeCallBack?(strongSelf.getEncodeData())
            }
            .disposed(by: disposeBag)
    }
    
    open func save() {
        
    }
    
    open func set(encodeData: Any?) {
        fatalError()
    }
    
    open func set(data: T?) {
        self.data = data
        
        save()
        
        dataObservable.onNext(data)
    }
    
    open func getEncodeData() -> Any? {
        fatalError()
    }
    
    open func update(encodeItem: Any) {
        fatalError()
    }
    
    open func update(itemId: String, key: String, value: Any?) {
        fatalError()
    }
    
    open func add(encodeItem: Any) {
        fatalError()
    }
    
    open func insert(encodeItem: Any) {
        fatalError()
    }
    
    open func getEncodeItem(index: Int) -> Any? {
        fatalError()
    }
    
    open func getEncodeItem(itemId: String) -> Any? {
        fatalError()
    }
    
    open func removeItem(itemId: String) {
        fatalError()
    }
}

open class DataRepository<T: Codable>: BaseDataRepository<T> {
    open override func set(encodeData: Any?) {
        if let data = encodeData as? [String: Any] {
            set(data: try? CodableBuilder().createDictionaryDecoder()
                .decode(T.self, from: data))
        } else {
            set(data: nil)
        }
    }
    
    open override func getEncodeData() -> Any? {
        guard let data = data else {
            return nil
        }
        
        do {
            let encodeData: [String: Any] = try CodableBuilder()
                .createDictionaryEncoder().encode(data)
            return encodeData
        } catch {
            logger.error("\(error.localizedDescription)")
            return nil
        }
    }
}

open class MapDataRepository: BaseDataRepository<[String: Any]> {
    open override func set(encodeData: Any?) {
        if let data = encodeData as? [String: Any] {
            set(data: data)
        } else {
            set(data: nil)
        }
    }
    
    open override func getEncodeData() -> Any? {
        return data
    }
}
